home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_075 / setfont / setfont.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  16KB  |  417 lines

  1. /* SetFont 2.0    -
  2.  
  3.         by Dave Haynie
  4.             BIX:    hazy
  5.             Usenet:    {allegra|caip|ihnp4}!cbmvax!daveh
  6.             Drink:    Guiness
  7.  
  8.    BUSINESS (MUNDANE, BUT IMPORTANT):
  9.  
  10.     This program is written by me, Dave Haynie, as mentioned above.
  11.    I have, however, placed it in the PUBLIC DOMAIN.  That, of course, means
  12.    that you can do (almost) absolutely anything with it.  You may hack it
  13.    to bits, include it with YOUR product, sell it, GIVE IT AWAY, or anything
  14.    else you like.  Of course, since anyone else can also give it away, it
  15.    would be foolish to stick your name on it and try to sell it.  I really
  16.    would like everyone to give it away, nicely, without being mean about it.
  17.    If you want to use it with your product, do that too, new products for
  18.    the Amiga are generally a good thing for the entire Amiga community.  You
  19.    can take bit and pieces and use them in your own programs, or the whole
  20.    thing for that matter.  And if you really want to have fun, you can even
  21.    IMPROVE this program, as its far from perfect, and give YOUR version 
  22.    away too, if you're so inclined.  That's about it for the (mundane)
  23.    business section, let's get on to the (interesting) notes section.
  24.  
  25.    ABOUT IT:
  26.  
  27.     This program is designed to allow you to set the font of a console
  28.    window (or really, a general WorkBench window) to any font, ROM or disk
  29.    based, that you have in mind.  This works much better than the first
  30.    version, in that it allows a greater variety of things to be changed
  31.    in the WorkBench.  What, you say, a VARIETY of things?  Well, lemme
  32.    explain....
  33.  
  34.        First off, something about fonts.  Amiga fonts all over the place
  35.    default to one of two ROM fonts, as specified in Preferences.  A ROM font
  36.    is just a font that happens to stored in with the KickStart code, instead
  37.    of out on a disk.  Since anything ever running on any Amiga can get to 
  38.    these fonts, they're used very heavily, perhaps too much.  If you've 
  39.    ever used the NotePad, however, you will probably have used some other
  40.    fonts.  These fonts are available on disk, and in fact, you can use
  41.    FontEd to create a variety of disk fonts for your own use.
  42.  
  43.    Whether disk or ROM, most programs use the Amiga's font management
  44.    utilities, which are part of the KickStart based graphics library.  But
  45.    very few folks just look at the graphics library.  Most everyone looks 
  46.    at Intuition.  Intuition manages things like screens and windows, and
  47.    you can write things to both screens and windows.  And, perhaps not
  48.    coincidentally, both screens and windows have some idea of what font they
  49.    should use, providing they've been given no special directions toward
  50.    using some other fonts.  The screen stores a pointer to a critter called
  51.    a "TextAttr", which is essentially a DESCRIPTOR for a font.  A TextAttr
  52.    contains the name of the font, the point size of the font, and a little
  53.    more information related to the font.  Both screens and windows also
  54.    contains a graphics structure, called a RastPort, which points to the
  55.    memory used to store the displayed memory.  The RastPort sports a pointer
  56.    to a different critter, the "TextFont".  The is the actual font, which is
  57.    the result of passing a TextAttr to one of the font opening functions.
  58.  
  59.        In this version I allow you to change the screen's font information,
  60.    like before, but I also know a bit more about the console window now.
  61.    When I open a window within a screen, such as the WorkBench screen, 
  62.    it's RastPort gets its default font from the screen's TextAttr font 
  63.    descriptor.  If this window is going to be a console window, it will
  64.    build a ConUnit, which has its own idea of the current font, based on
  65.    the window's font when it is created.  I can use the ROM Kernal SetFont()
  66.    call to change the font of the Window's RastPort.  Then I send an "<ESC>c"
  67.    to the console which will reinitialize the ConUnit from the window (and
  68.    also clear the screen....oh well).
  69.  
  70.     I need pointers to the window and screen to do this.  Since the 
  71.    Window structure contains a pointer to its screen, my goal is to find
  72.    the window associated with the calling console.  The best way I've found
  73.    for this is by setting up the current console as an I/O item, then
  74.    calling the DOS Info() function, which will return a pointer to the
  75.    console's window.  From this window I can get a the screen pointer and
  76.    the window's RastPort, so the fonts can be put in place.  When the
  77.    Screen's TextAttr is changed, I only change the values of that font
  78.    descriptor that the user's asked me to change.  Occasionally, this can
  79.    result in a few bytes of unreclaimed memory, as in font names:  I have no
  80.    idea how much memory is reserved in the screen's TextAttr structure on
  81.    startup.  I use the SetFont() function to set the window's or screen's
  82.    RastPort fonts.
  83.  
  84.     There are a few potential problems with my scheme.  First of all,
  85.    many programs are written to support only the topaz 8 (80 column) font
  86.    (sloppy, I know, but that's life).  If you're a 60 column user, you've 
  87.    probably experienced this before.  It's not a problem with the Amiga as
  88.    a whole, since most of the system will adjust itself.  But it may be a
  89.    problem with programs that have a fixed idea of what a font should look
  90.    like.  Most 80 column fonts work with most applications, and an 80 column
  91.    8x8 font will work just about everywhere.  Some programs, like CLI for 
  92.    instance, have trouble with proportionally-spaced fonts.  The best thing to
  93.    to is try out the font you like.  One final problem is that some
  94.    applications ask the WorkBench screen to close when they start up.  It'll
  95.    close if there's nothing else open on it, but when it re-opens, it'll
  96.    restart with the Preferences-selected font, not the SetFont selected font.
  97.    Of course, preferences doesn't support arbitrary fonts (which is why this
  98.    program is even necessary).  Oh well, maybe in 1.3?  The solution to this
  99.    is to  always keep at least one window open, so that WorkBench will never 
  100.    be closed on you.
  101. */
  102.  
  103. #include <exec/types.h>
  104. #include <exec/io.h>
  105. #include <exec/ports.h>
  106. #include <exec/memory.h>
  107. #include <graphics/gfxbase.h>
  108. #include <graphics/text.h>
  109. #include <graphics/rastport.h>
  110. #include <libraries/diskfont.h>
  111. #include <libraries/dos.h>
  112. #include <libraries/dosextens.h>
  113. #include <libraries/diskfont.h>
  114. #include <intuition/intuitionbase.h>
  115. #include <stdio.h>
  116.  
  117. /* ========================================================================= */
  118.  
  119. /* External things */
  120.  
  121. extern struct Library *OpenLibrary();
  122. extern struct TextFont *OpenFont();
  123. extern struct TextFont *OpenDiskFont();
  124. extern struct Window *OpenWindow();
  125.  
  126. extern char *strcat();
  127. extern char *strcpy();
  128. extern long strlen();
  129.  
  130. /* ========================================================================= */
  131.  
  132. /* Global variables */
  133.  
  134. struct GfxBase *GfxBase = NULL;
  135. struct Library *DiskfontBase = NULL;
  136. struct IntuitionBase *IntuitionBase = NULL;
  137.  
  138. struct MsgPort portblk = { 
  139.    {0L, 0L, NT_MSGPORT, 0, 0L}, 0, -1, 0L, 
  140.    {&portblk.mp_MsgList.lh_Tail, 0L, &portblk.mp_MsgList.lh_Head, 0, 0} 
  141. }; 
  142. struct MsgPort *port = &portblk;
  143.  
  144. struct IOStdReq reqblk = { 
  145.     {{0L, 0L, 0, 0, 0L}, &portblk, 0}, 0L, 0L, 0, 0, 0, 0L, 0L, 0L, 0L
  146. }; 
  147. struct IOStdReq *request = &reqblk;
  148.  
  149. struct Window *window = NULL;
  150. struct Screen *screen = NULL;
  151.  
  152. /* ========================================================================= */ 
  153.  
  154. /* This section contains startup and shutdown functions. */
  155.  
  156. /* This function opens the required Amiga libraries, devices, and other
  157.    good stuff.  It returns TRUE if successful.  Graphics, Intuition, and
  158.    DiskFont libraries are opened. The console device is opened and the 
  159.    I/O request message port is initialized.  I also do a check to make sure
  160.    that the associated Task is really a Process.  This is absolutely 
  161.    necessary, as some of the functions that I'll be using later are DOS
  162.    functions, which require Processes, not Tasks.  */
  163.  
  164. BOOL OpenUp()
  165. {
  166.    /* The Libraries */
  167.  
  168.    if ((GfxBase = (struct GfxBase *) 
  169.       OpenLibrary("graphics.library", 0L)) == NULL) return FALSE;
  170.    if ((DiskfontBase = OpenLibrary("diskfont.library",0L)) == NULL) return FALSE;
  171.    if ((IntuitionBase = (struct IntuitionBase *)
  172.       OpenLibrary("intuition.library", 0L)) == NULL) return FALSE;
  173.  
  174.    /* The Devices */
  175.  
  176.    if ((OpenDevice("console.device", -1L, request, 0L)) != 0L) return FALSE;
  177.    if ((port->mp_SigBit = AllocSignal(-1L)) < 0L) return FALSE;
  178.    port->mp_SigTask = (struct Task *) FindTask((char *) NULL); 
  179.    if (port->mp_SigTask->tc_Node.ln_Type != NT_PROCESS) return FALSE;
  180.    return TRUE;
  181. }
  182.  
  183. /* This function frees up dynamically opened things, like the devices
  184.    and the libraries, opened above. */
  185.  
  186. void ShutDown()
  187.    if (request->io_Device != NULL) { 
  188.       if (port->mp_SigBit != -1) FreeSignal(port->mp_SigBit); 
  189.       CloseDevice(request); 
  190.    } 
  191.    if (IntuitionBase != NULL) CloseLibrary(IntuitionBase); 
  192.    if (DiskfontBase != NULL) CloseLibrary(DiskfontBase);
  193.    if (GfxBase != NULL) CloseLibrary(GfxBase);
  194.  
  195. /* ========================================================================= */
  196.  
  197. /* Attribute based functions. */
  198.  
  199. /* This function allocates space for the given font descriptor, converting
  200.    the point size into a numeric form at the same time. */
  201.  
  202. struct TextAttr *AllocAttr(fontname, pointname)
  203. char *fontname, *pointname;
  204. {
  205.    short point;
  206.    char *str;
  207.    struct TextAttr *attr = NULL;
  208.  
  209.    attr = (struct TextAttr *) AllocMem(sizeof(*attr),0L);
  210.  
  211.    if (pointname == NULL) point = 8;
  212.    else point = atoi(pointname);
  213.  
  214.    str = (char *) AllocMem(strlen(fontname)+6L,0L);
  215.    strcpy(str,fontname);
  216.    strcat(str,".font");
  217.    attr->ta_Name = str;
  218.    attr->ta_YSize = point;
  219.    attr->ta_Style = 0;
  220.    attr->ta_Flags = 0;
  221.    return attr;
  222. }
  223.  
  224. /* This function frees a TextAttr allocated with AllocAttr(). */
  225.  
  226. void FreeAttr(attr)
  227. struct TextAttr *attr;
  228. {
  229.    if (attr == NULL) return;
  230.    FreeMem(attr->ta_Name, strlen(attr->ta_Name));
  231.    FreeMem(attr,sizeof(*attr));
  232. }
  233. /* ========================================================================= */
  234.  
  235. /* This function allocates a packet and associated info block.  It returns
  236.    a pointer to this packet if successful, NULL otherwise. */
  237.  
  238. struct StandardPacket *AllocInfoPacket()
  239. {
  240.    struct StandardPacket *pac = NULL;
  241.    struct InfoData *inf = NULL;
  242.  
  243.    pac = (struct StandardPacket *) AllocMem(sizeof(*pac), MEMF_CLEAR);
  244.    if (pac == NULL) return NULL;
  245.    inf = (struct InfoData *) AllocMem(sizeof(*inf), MEMF_CLEAR);
  246.    if (inf == NULL) {
  247.       FreeMem(pac,sizeof(*pac));
  248.       return NULL;
  249.    }
  250.    pac->sp_Msg.mn_Node.ln_Name = (char *) &(pac->sp_Pkt); 
  251.    pac->sp_Pkt.dp_Link = &(pac->sp_Msg); 
  252.    pac->sp_Pkt.dp_BufAddr = ((ULONG) inf) >> 2; 
  253.    pac->sp_Pkt.dp_Type = ACTION_DISK_INFO; 
  254.  
  255.    return pac;
  256. }
  257.  
  258. /* ========================================================================= */
  259.  
  260. /* This function gets the Window pointer for the current console.  It 
  261.    takes the message port for the console.  It uses the fact that the I/O
  262.    device's message port points to the process associated with this CLI.  
  263.    This process needs a console window, and it should have a pointer to a
  264.    message port for this purpose.  We use DOS packets to request an
  265.    InfoData block on this console window.  The window pointer is passed 
  266.    back as the volume name of the console.  We're getting into DOS, so look
  267.    out for BCPL pointers and longword alignment! */
  268.  
  269. struct Window *GetConsoleWindow(port)
  270. struct MsgPort *port;
  271. {
  272.    struct MsgPort *cp;             /* Console port */
  273.    struct InfoData *inf;        /* Packet data block */
  274.    struct StandardPacket *pac = NULL;   /* Packet for DOS request */
  275.    struct Window *w = NULL;        /* Resulting Window */
  276.  
  277.    cp = (struct MsgPort *)((struct Process *)port->mp_SigTask)->pr_ConsoleTask; 
  278.    if (cp == 0L) return NULL;
  279.  
  280.    if ((pac = AllocInfoPacket()) == NULL) return NULL;
  281.    pac->sp_Pkt.dp_Port = port; 
  282.    inf = (struct InfoData *) (((ULONG) pac->sp_Pkt.dp_BufAddr) << 2);
  283.    PutMsg(cp, pac); 
  284.    WaitPort(port); 
  285.    w = (struct Window *) inf->id_VolumeNode;
  286.    FreeMem(inf, sizeof(*inf));
  287.    FreeMem(pac, sizeof(*pac));
  288.  
  289.    return w;
  290. }
  291.  
  292. /* ========================================================================= */
  293.  
  294. /* This function tries to get a requested font from an attribute descriptor;
  295.    it returns FALSE if the font doesn't exit. */
  296.  
  297. struct TextFont *GetFont(attr)
  298. struct TextAttr *attr;
  299. {
  300.    struct TextFont *font;
  301.    
  302.    if ((font = OpenDiskFont(attr)) != NULL) return font;
  303.    if ((font = OpenFont(attr)) != NULL) return font;
  304.    return NULL;
  305. }
  306.  
  307. /* ========================================================================= */
  308.  
  309. /* The main function */
  310.  
  311. main(argc, argv) 
  312. int argc; 
  313. char *argv[]; 
  314.    short i;
  315.    BOOL printmode = FALSE;
  316.    BOOL mode_screen = FALSE;
  317.    BOOL mode_title = FALSE;
  318.    BOOL mode_window = FALSE;
  319.    struct TextAttr *attr = NULL;
  320.    struct TextFont *newfont, *oldfont;
  321.  
  322.    /* Automatic help command */
  323.  
  324.    if (argc == 1) printmode = TRUE;
  325.    else if (argv[1][0] == '?') {
  326.       printf("SetFont 2.0 by Dave Haynie\n\n");
  327.       printf("Usage: SetFont [fontname [point [place]]], where\n\n");
  328.       printf("  \2331mfontname\2330m  is the font's name (e.g. \"topaz\")\n");
  329.       printf("  \2331mpoint\2330m     is the point size (default is 8)\n");
  330.       printf("  \2331mplace\2330m     pick the place, one or more of:\n");
  331.       printf("    \2331mSCREEN\2330m    set the screen font only\n");
  332.       printf("    \2331mTITLES\2330m    set the screen titles only\n");
  333.       printf("    \2331mWINDOW\2330m    set the window's font only\n\n");
  334.       printf("If no \2331mplace\2330m switch is given, everything is set.\n");
  335.       Exit(10);
  336.    }
  337.  
  338.    /* Process the command-line arguments, AmigaDOS style. */
  339.  
  340.    for (i=3; i<argc; i++)
  341.       if (argv[i][0] == 'T' || argv[i][0] == 't')      mode_title = TRUE;
  342.       else if (argv[i][0] == 'S' || argv[i][0] == 's') mode_screen = TRUE;
  343.       else if (argv[i][0] == 'W' || argv[i][0] == 'w') mode_window = TRUE;
  344.    if (!mode_title && !mode_screen && !mode_window)
  345.       mode_title = mode_screen = mode_window = TRUE;
  346.    
  347.    /* First all, we've got to open all the good stuff. */
  348.  
  349.    if (!OpenUp() || (window=GetConsoleWindow(port)) == NULL) {
  350.       ShutDown();
  351.       Exit(10);
  352.    }
  353.  
  354.    /* Process the informational print mode, real simple */
  355.  
  356.    if (printmode) {
  357.       printf("SetFont 2.0 by Dave Haynie\n\n");
  358.       attr = window->WScreen->Font;
  359.       printf("Screen Font: %s (%ld) ", attr->ta_Name, attr->ta_YSize);
  360.       printf("Style %ld, Flags %ld\n", attr->ta_Style, attr->ta_Flags);
  361.       ShutDown();
  362.       Exit(0);
  363.    }
  364.  
  365.    /* Get the attribute and font, where available. */
  366.  
  367.    attr = AllocAttr(argv[1], argv[2]);
  368.    if ((newfont = GetFont(attr)) == NULL) {
  369.       printf("Error: Font not found\n");
  370.       FreeAttr(attr);
  371.       ShutDown(); 
  372.       Exit(10);
  373.    }
  374.  
  375.    /* Here's where the various options are processed individually. */
  376.  
  377.    /* The screen titling  font is changed via a SetFont() call to the 
  378.       screen's RastPort.  */
  379.  
  380.    if (mode_title) {
  381.       oldfont = window->WScreen->RastPort.Font;
  382.       if (SetFont(&window->WScreen->RastPort,newfont) == 0) CloseFont(oldfont);
  383.    }
  384.  
  385.    /* If the current font is the same font, we can just change the point
  386.       size attribute value.  If its a completely new font, the entire
  387.       attribute pointer is reassigned.  This may not be necessary, but it
  388.       works this way, and I've had trouble with other schemes.  */
  389.  
  390.    if (mode_screen) {
  391.       if (strcmp(window->WScreen->Font->ta_Name,attr->ta_Name) == 0) {
  392.          window->WScreen->Font->ta_YSize = attr->ta_YSize;
  393.          FreeAttr(attr);
  394.       } else
  395.          window->WScreen->Font = attr;
  396.    }
  397.  
  398.    /* The window font is changed via a SetFont() call to the window's
  399.       RastPort, much in the same way that the screen's titling fonts are
  400.       changed.  Additionally, the console device must be reset to force
  401.       the ConUnit to be rebuit, which draws the new font from the
  402.       window.  */
  403.  
  404.    if (mode_window) {
  405.       oldfont = window->RPort->Font;
  406.       if (SetFont(window->RPort,newfont) != 0L) CloseFont(oldfont);
  407.       printf("\033c");
  408.    }
  409.    CloseFont(newfont);
  410.    ShutDown();
  411.    Exit(0);
  412. }
  413.  
  414.